home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection Student Program / ADC Tools Sampler CD Disk 3 1999.iso / Metrowerks CodeWarrior / Java Support / Java_Source / IFC_112 / netscape / application / TextSelection.java < prev    next >
Encoding:
Text File  |  1999-05-28  |  17.9 KB  |  579 lines  |  [TEXT/CWIE]

  1. // TextSelection.java
  2. // By Ned Etcode
  3. // Copyright 1995, 1996, 1997 Netscape Communications Corp.  All rights reserved.
  4.  
  5. package netscape.application;
  6.  
  7. import netscape.util.*;
  8.  
  9. /** Object subclass that maintains a TextView's selection information and
  10.   * also manages its insertion point blinking.<br><br>
  11.   * @note 1.0 changes
  12.   */
  13. class TextSelection implements Target {
  14.     TextView            _owner;
  15.     private TextParagraph       _editParagraph;
  16.     TextPositionInfo    _insertionPointInfo, _anchorPositionInfo,
  17.                         _endPositionInfo;
  18.     Timer               _blinkTimer;
  19.     long                _lastFlashTime;
  20.     int                 _anchorPosition, _endPosition;
  21.     boolean             _flashInsertionPoint, _insertionPointShowing,
  22.                         _ignoreNextFlash;
  23.     boolean             _selectionDefined;
  24.     int                 _insertionPointDisabled;
  25.  
  26.  
  27. /* constructors */
  28.      TextSelection() {
  29.         super();
  30.         _selectionDefined = false;
  31.     }
  32.  
  33.      TextSelection(TextView textView) {
  34.         this();
  35.         init(textView);
  36.         _selectionDefined = false;
  37.     }
  38.  
  39.  
  40.  
  41. /* initializers */
  42.  
  43.  
  44.      void init(TextView owner) {
  45.         _owner = owner;
  46.  
  47.     }
  48.  
  49.     void _startFlashing() {
  50.  
  51.         if( _insertionPointDisabled != 0)
  52.             return;
  53.  
  54.         if(!_owner.isEditable())
  55.             return;
  56.  
  57.         if(! _selectionDefined )
  58.             return;
  59.         if( _blinkTimer == null )
  60.             _blinkTimer = new Timer(this, "blinkCaret", 700);
  61.  
  62.         if (_owner.isEditing()) {
  63.             _blinkTimer.start();
  64.         } else if ((System.currentTimeMillis() - _lastFlashTime > 350)) {
  65.           /* if almost time to blink again, don't */
  66.             _ignoreNextFlash = true;
  67.         }
  68.         showInsertionPoint();
  69.     }
  70.  
  71.     void _stopFlashing() {
  72.         hideInsertionPoint();
  73.         if (_blinkTimer != null) {
  74.             _blinkTimer.stop();
  75.             _ignoreNextFlash = false;
  76.         }
  77.     }
  78.  
  79.     public void performCommand(String command, Object data) {
  80.         if (_owner.isEditing() && _selectionDefined) {
  81.             /* toggle insertion point */
  82.             if (_ignoreNextFlash || !_flashInsertionPoint || isARange()) {
  83.                 _ignoreNextFlash = false;
  84.                 return;
  85.             }
  86.  
  87.             _lastFlashTime = _blinkTimer.timeStamp();
  88.  
  89.             _insertionPointShowing = !_insertionPointShowing;
  90.  
  91.             _owner.drawInsertionPoint();
  92.         } else if (_blinkTimer != null) {
  93.             /* stop flashing */
  94.             _blinkTimer.stop();
  95.         }
  96.     }
  97.  
  98.     boolean isARange() {
  99.         return (_insertionPointInfo == null && _anchorPositionInfo != null);
  100.     }
  101.  
  102.     void disableInsertionPoint() {
  103.         if( _insertionPointDisabled == 0 )
  104.             hideInsertionPoint();
  105.         _insertionPointDisabled++;
  106.     }
  107.  
  108.     void enableInsertionPoint() {
  109.         _insertionPointDisabled--;
  110.         if( _insertionPointDisabled == 0 )
  111.             showInsertionPoint();
  112.     }
  113.     void showInsertionPoint() {
  114.         if( _insertionPointDisabled != 0 )
  115.             return;
  116.  
  117.         if(!_owner.isEditable())
  118.             return;
  119.  
  120.         if( ! _owner.isEditing())
  121.             return;
  122.  
  123.         _flashInsertionPoint = true;
  124.  
  125.         if (isARange() || _insertionPointShowing) {
  126.             return;
  127.         }
  128.  
  129.         _insertionPointShowing = true;
  130.  
  131.         _owner.drawInsertionPoint();
  132.  
  133.         _startFlashing();
  134.     }
  135.  
  136.     void hideInsertionPoint() {
  137.         _flashInsertionPoint = false;
  138.  
  139.         if (isARange() || !_insertionPointShowing) {
  140.             return;
  141.         }
  142.  
  143.         _insertionPointShowing = false;
  144.  
  145.         _owner.drawInsertionPoint();
  146.     }
  147.  
  148.     Rect insertionPointRect() {
  149.         if (_insertionPointInfo == null) {
  150.             return TextView.newRect();
  151.         }
  152.  
  153.         return TextView.newRect(_insertionPointInfo._x - 1,
  154.                                 _insertionPointInfo._y, 1,
  155.                                 _insertionPointInfo._lineHeight);
  156.     }
  157.  
  158.     Rect _updateRectForInfo(int oldPoint, int newPoint,
  159.                             TextPositionInfo oldInfo,
  160.                             TextPositionInfo newInfo) {
  161.         Rect    tmpRect, updateRect;
  162.  
  163.       /* did the selection point change? */
  164.         if (oldPoint == newPoint) {
  165.             return null;
  166.         }
  167.  
  168.       /* if on the same line, just redraw the update rect */
  169.         if (oldInfo._y == newInfo._y) {
  170.             if (newInfo._x < oldInfo._x) {
  171.                 updateRect = TextView.newRect(newInfo._x, newInfo._y,
  172.                                               oldInfo._x - newInfo._x,
  173.                                               newInfo._lineHeight);
  174.             } else {
  175.                 updateRect = TextView.newRect(oldInfo._x, newInfo._y,
  176.                                              newInfo._x - oldInfo._x,
  177.                                              newInfo._lineHeight);
  178.             }
  179.         } else {
  180.             updateRect = oldInfo.lineBounds();
  181.             tmpRect = newInfo.lineBounds();
  182.             updateRect.unionWith(tmpRect);
  183.             TextView.returnRect(tmpRect);
  184.         }
  185.  
  186.         return updateRect;
  187.     }
  188.  
  189.  
  190.  
  191.      void setRange(int selectionBegin, int selectionEnd,
  192.                          TextPositionInfo selectionEndInfo,
  193.                          boolean selectLineBreak,boolean fromBottom) {
  194.         TextPositionInfo        oldStartInfo, oldEndInfo, newStartInfo,
  195.                                 newEndInfo;
  196.         Rect                    updateRect, anchorRect, endRect, startRect,
  197.                                 tmpRect;
  198.         int                     oldStart, oldEnd, newStart, newEnd;
  199.  
  200.         if( selectionBegin == -1 ||
  201.             selectionEnd   == -1 )
  202.             _selectionDefined = false;
  203.         else
  204.             _selectionDefined = true;
  205.  
  206.         if (_anchorPosition != _endPosition) {
  207.             oldStart = (_anchorPosition < _endPosition ?
  208.                                 _anchorPosition : _endPosition);
  209.             oldStartInfo = (_anchorPosition < _endPosition ?
  210.                                 _anchorPositionInfo : _endPositionInfo);
  211.             oldEnd = (_anchorPosition > _endPosition ?
  212.                                 _anchorPosition : _endPosition);
  213.             oldEndInfo = (_anchorPosition > _endPosition ?
  214.                                 _anchorPositionInfo : _endPositionInfo);
  215.         } else {
  216.             oldStart = oldEnd = -1;
  217.             oldStartInfo = oldEndInfo = null;
  218.         }
  219.  
  220.       /* make sure range is valid */
  221.         if (selectionBegin < 0) {
  222.             selectionBegin = 0;
  223.         } else if (selectionBegin >= _owner._charCount) {
  224.             selectionBegin = _owner._charCount - 1;
  225.         }
  226.         if (selectionEnd < 0) {
  227.             selectionEnd = 0;
  228.         } else if (selectionEnd >= _owner._charCount) {
  229.             selectionEnd = _owner._charCount - 1;
  230.         }
  231.  
  232.         _anchorPosition = selectionBegin;
  233.         _endPosition = selectionEnd;
  234.  
  235.         if (_anchorPosition == _endPosition) {
  236.             _editParagraph = _owner._paragraphForIndex(_anchorPosition);
  237.             _insertionPointInfo = _editParagraph.infoForPosition(
  238.                                                         _anchorPosition, -1);
  239.             if( fromBottom && _insertionPointInfo._endOfLine && _anchorPosition < (_owner.length()-1)) {
  240.                 TextParagraph nextParagraph = _owner._paragraphForIndex(_anchorPosition+1);
  241.                 if( nextParagraph == _editParagraph ) {
  242.                     TextPositionInfo nextPositionInfo =
  243.                         _editParagraph.infoForPosition(_anchorPosition + 1,-1);
  244.                     if( nextPositionInfo._y > _insertionPointInfo._y )
  245.                         _insertionPointInfo = _editParagraph.infoForPosition(_anchorPosition,
  246.                                                         nextPositionInfo._y);
  247.                 }
  248.             }
  249.             _anchorPositionInfo = _endPositionInfo = null;
  250.         } else {
  251.             TextParagraph p;
  252.             p = _owner._paragraphForIndex(_anchorPosition);
  253.             _anchorPositionInfo = p.infoForPosition(_anchorPosition, -1);
  254.             if( _anchorPositionInfo._endOfLine && !selectLineBreak ) {
  255.                 _anchorPositionInfo = p.infoForPosition(_anchorPosition, _anchorPositionInfo.maxY());
  256.             }
  257.             if (selectionEndInfo == null) {
  258.                 _endPositionInfo = _owner._paragraphForIndex(
  259.                                         _endPosition).infoForPosition(
  260.                                                         _endPosition, -1);
  261.             } else {
  262.                 _endPositionInfo = selectionEndInfo;
  263.             }
  264.  
  265.             _insertionPointInfo = null;
  266.             _editParagraph = null;
  267.         }
  268.  
  269.         if (_anchorPosition != _endPosition) {
  270.             newStart = (_anchorPosition < _endPosition ?
  271.                                 _anchorPosition : _endPosition);
  272.             newStartInfo = (_anchorPosition < _endPosition ?
  273.                                 _anchorPositionInfo : _endPositionInfo);
  274.             newEnd = (_anchorPosition > _endPosition ?
  275.                                 _anchorPosition : _endPosition);
  276.             newEndInfo = (_anchorPosition > _endPosition ?
  277.                                 _anchorPositionInfo : _endPositionInfo);
  278.         } else {
  279.             newStart = newEnd = -1;
  280.             newStartInfo = newEndInfo = null;
  281.         }
  282.  
  283.       /* old selection was just an insertionPoint */
  284.         if (oldStart == -1) {
  285.           /* if still just an insertionPoint, we're done */
  286.             if (newStart == -1) {
  287.                 _startFlashing();
  288.                 _updateCurrentFont();
  289.                 return;
  290.             }
  291.  
  292.           /* redraw from new selection start to new selection end */
  293.             dirtyRangeForSelection(_anchorPositionInfo,_endPositionInfo,null,null);
  294.             _updateCurrentFont();
  295.             return;
  296.         } else if (newStart == -1) {
  297.           /*
  298.            * new selection is just an insertionPoint, so redraw from old
  299.            * selection start to old selection end
  300.            */
  301.             dirtyRangeForSelection(oldStartInfo,oldEndInfo,null,null);
  302.  
  303.             _startFlashing();
  304.             _updateCurrentFont();
  305.             return;
  306.         } else { /* Both ranges */
  307.             dirtyRangeForSelection(newStartInfo,newEndInfo,oldStartInfo,oldEndInfo);
  308.         }
  309.  
  310.         _updateCurrentFont();
  311.      }
  312.  
  313.      void dirtyRangeForSelection(TextPositionInfo start,TextPositionInfo end,
  314.                                  TextPositionInfo previousStart,TextPositionInfo previousEnd) {
  315.         Range isr,nsr,dirtyRange;
  316.         Vector dirtyRects;
  317.         Rect rect,result = null;
  318.         int i,c;
  319.         Rect bounds = _owner.bounds();
  320.  
  321.         nsr = Range.rangeFromIndices(start._absPosition,end._absPosition);
  322.         if( previousStart == null || previousEnd == null ) {
  323.             dirtyRange = nsr;
  324.         } else {
  325.             isr = Range.rangeFromIndices(previousStart._absPosition,previousEnd._absPosition);
  326.             if( isr.equals(nsr))
  327.                 return;
  328.  
  329.             if(nsr.index == isr.index ) {
  330.                 if( nsr.length > isr.length )
  331.                     dirtyRange = new Range(nsr.index + isr.length,
  332.                                            nsr.length - isr.length);
  333.                 else
  334.                     dirtyRange = new Range(nsr.index + nsr.length,
  335.                                            isr.length - nsr.length);
  336.             } else if( (nsr.index + nsr.length) == (isr.index + isr.length)) {
  337.                 if( nsr.length > isr.length )
  338.                     dirtyRange = new Range( nsr.index,nsr.length - isr.length);
  339.                 else
  340.                     dirtyRange = new Range( isr.index,isr.length - nsr.length);
  341.             } else {
  342.                 /* We are not dragging the selection. We change it.
  343.                  * it is faster to refresh two ranges than the union
  344.                  * of two
  345.                  */
  346.                 dirtyRangeForSelection(start,end,null,null);
  347.                 dirtyRangeForSelection(previousStart,previousEnd,null,null);
  348.                 return;
  349.             }
  350.         }
  351.  
  352.  
  353.         dirtyRects  = _owner.rectsForRange( dirtyRange );
  354.  
  355.         for(i=0,c=dirtyRects.count() ; i < c ; i++ ) {
  356.             rect = (Rect) dirtyRects.elementAt(i);
  357.  
  358.             rect.x = 0;
  359.             rect.width = bounds.width;
  360.  
  361.             if( rect.height > 0 ) {
  362.                 if( result == null )
  363.                     result = new Rect( rect );
  364.                 else
  365.                     result.unionWith( rect );
  366.             }
  367.         }
  368.  
  369.         if( result == null ) {
  370.              return;
  371.         }
  372.  
  373.          if(dirtyRange.contains(start._absPosition) &&
  374.             !result.contains(start._x,start._y) && start._absPosition > 0) {
  375.              TextPositionInfo previousLineInfo = _owner.positionInfoForIndex(
  376.                                                      start._absPosition-1);
  377.              if( previousLineInfo != null ) {
  378.                  result.y -= previousLineInfo._lineHeight;
  379.                  result.height += previousLineInfo._lineHeight;
  380.              }
  381.          }
  382.  
  383.          if(dirtyRange.contains(end._absPosition) &&
  384.             !result.contains(end._x,end._y) && end._absPosition > 0) {
  385.              TextPositionInfo previousLineInfo = _owner.positionInfoForIndex(
  386.                                                      end._absPosition-1);
  387.              if( previousLineInfo != null ) {
  388.                  result.y -= previousLineInfo._lineHeight;
  389.                  result.height += previousLineInfo._lineHeight;
  390.              }
  391.          }
  392.  
  393.  
  394.          if(previousStart != null && dirtyRange.contains(previousStart._absPosition) &&
  395.             !result.contains(previousStart._x,previousStart._y) &&
  396.             previousStart._absPosition > 0) {
  397.              TextPositionInfo previousLineInfo = _owner.positionInfoForIndex(
  398.                                                      previousStart._absPosition-1);
  399.              if( previousLineInfo != null ) {
  400.                  result.y -= previousLineInfo._lineHeight;
  401.                  result.height += previousLineInfo._lineHeight;
  402.              }
  403.          }
  404.  
  405.          if(previousEnd != null && dirtyRange.contains(previousEnd._absPosition) &&
  406.             !result.contains(previousEnd._x,previousEnd._y) && previousEnd._absPosition > 0) {
  407.              TextPositionInfo previousLineInfo = _owner.positionInfoForIndex(
  408.                                                      previousEnd._absPosition-1);
  409.              if( previousLineInfo != null ) {
  410.                  result.y -= previousLineInfo._lineHeight;
  411.                  result.height += previousLineInfo._lineHeight;
  412.              }
  413.          }
  414.          //System.out.println("Updating range " + dirtyRange + " rect " + result);
  415.          _owner.addDirtyRect( result );
  416.      }
  417.  
  418.      void setRange(int selectionBegin, int selectionEnd,
  419.                          TextPositionInfo selectionEndInfo,
  420.                          boolean selectLineBreak) {
  421.          setRange(selectionBegin,selectionEnd,selectionEndInfo,selectLineBreak,false);
  422.      }
  423.  
  424.  
  425.      void setRange(int selectionBegin, int selectionEnd) {
  426.         setRange(selectionBegin, selectionEnd, null, false,false);
  427.     }
  428.  
  429.      void setRange(int selectionBegin, int selectionEnd, boolean fromBottom) {
  430.          setRange(selectionBegin,selectionEnd,null,false,fromBottom);
  431.      }
  432.  
  433.      void clearRange() {
  434.         hideInsertionPoint();
  435.         setRange(-1,-1);
  436.         _stopFlashing();
  437.     }
  438.  
  439.     void setInsertionPoint(TextPositionInfo positionInfo) {
  440.         Rect    updateRect = null, endRect;
  441.  
  442.         if (positionInfo == null) {
  443.             return;
  444.         }
  445.  
  446.         _selectionDefined = true;
  447.         if (_anchorPosition != _endPosition) {
  448.             updateRect = _anchorPositionInfo.lineBounds();
  449.             endRect = _endPositionInfo.lineBounds();
  450.  
  451.             updateRect.unionWith(endRect);
  452.             updateRect.x = 0;
  453.             updateRect.width = _owner.bounds.width;
  454.             TextView.returnRect(endRect);
  455.         }
  456.  
  457.       /* make the changes */
  458.         _anchorPosition = _endPosition = positionInfo._absPosition;
  459.         _insertionPointInfo = positionInfo;
  460.         _editParagraph = _insertionPointInfo._textRun._paragraph;
  461.  
  462.         _anchorPositionInfo = _endPositionInfo = null;
  463.  
  464.       /* update */
  465.         if (updateRect != null) {
  466.             _owner.draw(updateRect);
  467.             TextView.returnRect(updateRect);
  468.         }
  469.  
  470.         if (_insertionPointShowing) {
  471.             _startFlashing();
  472.         }
  473.     }
  474.  
  475.     int insertionPoint() {
  476.         if (isARange()) {
  477.             return -1;
  478.         }
  479.  
  480.         return _anchorPosition;
  481.     }
  482.  
  483.     TextPositionInfo insertionPointInfo() {
  484.         if (isARange()) {
  485.             return null;
  486.         }
  487.  
  488.         return _insertionPointInfo;
  489.     }
  490.  
  491.     int selectionStart() {
  492.         if( !_selectionDefined )
  493.             return -1;
  494.  
  495.         if (_anchorPosition <= _endPosition) {
  496.             return _anchorPosition;
  497.         }
  498.         return _endPosition;
  499.     }
  500.  
  501.     TextPositionInfo selectionStartInfo() {
  502.         if (!isARange()) {
  503.             return _insertionPointInfo;
  504.         }
  505.         if (_anchorPosition <= _endPosition) {
  506.             return _anchorPositionInfo;
  507.         }
  508.  
  509.         return _endPositionInfo;
  510.     }
  511.  
  512.     int selectionEnd() {
  513.         if( !_selectionDefined )
  514.             return -1;
  515.  
  516.         if (_endPosition > _anchorPosition) {
  517.             return _endPosition;
  518.         }
  519.  
  520.         return _anchorPosition;
  521.     }
  522.  
  523.     TextPositionInfo selectionEndInfo() {
  524.         if (!isARange()) {
  525.             return _insertionPointInfo;
  526.         }
  527.         if (_endPosition > _anchorPosition) {
  528.             return _endPositionInfo;
  529.         }
  530.  
  531.         return _anchorPositionInfo;
  532.     }
  533.  
  534.     void _updateCurrentFont() {
  535.     }
  536.  
  537.  
  538.  
  539.  
  540.     int orderedSelectionStart() {
  541.         if( !_selectionDefined )
  542.             return -1;
  543.  
  544.         return _anchorPosition;
  545.     }
  546.  
  547.     TextPositionInfo orderedSelectionStartInfo() {
  548.         if (!isARange()) {
  549.             return _insertionPointInfo;
  550.         }
  551.         return _anchorPositionInfo;
  552.     }
  553.  
  554.     int orderedSelectionEnd() {
  555.         if( !_selectionDefined )
  556.             return -1;
  557.  
  558.         return _endPosition;
  559.     }
  560.  
  561.     TextPositionInfo orderedSelectionEndInfo() {
  562.        if (!isARange()) {
  563.            return _insertionPointInfo;
  564.        }
  565.  
  566.        return _endPositionInfo;
  567.    }
  568. }
  569.  
  570.  
  571.  
  572.  
  573.  
  574.  
  575.  
  576.  
  577.  
  578.  
  579.